package com.ruoyi.web.controller.system;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import com.dtflys.forest.annotation.JSONBody;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.constant.IotConstants;
import com.ruoyi.common.core.page.PageDomain;
import com.ruoyi.common.core.page.TableSupport;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.es.domain.EsDeviceDataInfo;
import com.ruoyi.es.domain.EsDeviceInfo;
import com.ruoyi.es.domain.EsValueInfo;
import com.ruoyi.es.mapper.EsDeviceDataInfoMapper;
import com.ruoyi.es.mapper.EsDeviceInfoMapper;
import com.ruoyi.es.mapper.EsValueInfoMapper;
import com.ruoyi.system.domain.Forest.second.*;
import com.ruoyi.system.domain.SetIotParams;
import com.ruoyi.system.domain.cache.DeviceCache;
import com.ruoyi.system.domain.result.IotDeviceBindResult;
import com.ruoyi.system.service.*;
import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.SysDevice;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;

/**
 * 设备Controller
 * 
 * @author ruoyi
 * @date 2024-08-07
 */
@RestController
@RequestMapping("/system/device")
public class SysDeviceController extends BaseController
{
    @Autowired
    private ISysDeviceService sysDeviceService;

//    @Resource
//    private DeviceAsyncClient deviceAsyncClient;
    @Resource
    private SecondDeviceAsyncClient secondDeviceAsyncClient;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ISysBuildingService sysBuildingService;

//    @Autowired
//    private EsDeviceInfoMapper esDeviceInfoMapper;

    @Autowired
    private EsDeviceDataInfoMapper esDeviceInfoMapper;

    @Autowired
    private EsValueInfoMapper esValueInfoMapper;

    /**
     * 查询设备列表
     */
    @PreAuthorize("@ss.hasPermi('system:device:list')")
    @GetMapping("/list")
    public TableDataInfo list(SysDevice sysDevice)
    {
        startPage();
        if (!getDeptId().equals(100L)){
            sysDevice.setDeptId(getDeptId());
        }
        List<SysDevice> list = sysDeviceService.selectSysDeviceList(sysDevice);
        list.forEach(item ->{
            DeviceCache deviceCache = redisCache.getCacheObject(CacheConstants.IOT_DEVICE + item.getDeviceCode());
            if (item.getDeviceType().equals(IotConstants.DEVICE_TYPE_HEATING)) {
                if (deviceCache == null || deviceCache.getVolume() == null){
                    item.setVolume(0.0);
                }else {
                    item.setVolume(deviceCache.getVolume());
                }
                if (deviceCache == null || deviceCache.getHeatQuantity() == null){
                    item.setHeatQuantity(0.0);
                }else {
                    item.setHeatQuantity(deviceCache.getHeatQuantity());
                }
                if (deviceCache == null || deviceCache.getHeatPower() == null){
                    item.setHeatPower(0.0);
                }else {
                    item.setHeatPower(deviceCache.getHeatPower());
                }
                if (deviceCache == null || deviceCache.getFlowrateReal() == null){
                    item.setFlowrateReal(0.0);
                }else {
                    item.setFlowrateReal(deviceCache.getFlowrateReal());
                }
                if (deviceCache == null || deviceCache.getTempIntake() == null){
                    item.setTempIntake(new BigDecimal("0"));
                }else {
                    item.setTempIntake(deviceCache.getTempIntake());
                }
                if (deviceCache == null || deviceCache.getTempReturn() == null){
                    item.setTempReturn(new BigDecimal("0"));
                }else {
                    item.setTempReturn(deviceCache.getTempReturn());
                }
                if (deviceCache == null || deviceCache.getState() == null){
                    item.setState(0);
                }else {
                    item.setState(deviceCache.getState());
                }
                if (deviceCache == null || deviceCache.getHoursOperating() == null){
                    item.setHoursOperating(0);
                }else {
                    item.setHoursOperating(deviceCache.getHoursOperating());
                }
                if (deviceCache == null || deviceCache.getTimeUpload() == null){
                    item.setTimeUpload(null);
                }else {
                    item.setTimeUpload(deviceCache.getTimeUpload());
                }
                if (deviceCache == null || deviceCache.getTimeSample() == null){
                    item.setTimeSample(null);
                }else {
                    item.setTimeSample(deviceCache.getTimeSample());
                }

            }else if (item.getDeviceType().equals(IotConstants.DEVICE_TYPE_VALVE)){
                if (deviceCache == null || deviceCache.getTempSet() == null){
                    item.setSetTemp(new BigDecimal("0"));
                } else {
                    item.setSetTemp(deviceCache.getTempSet());
                }
                if (deviceCache == null || deviceCache.getTempIndoor() == null){
                    item.setTempIndoor(new BigDecimal("0"));
                }else {
                    item.setTempIndoor(deviceCache.getTempIndoor());
                }
                if (deviceCache == null || deviceCache.getWorkMode() == null){
                    item.setWorkMode(IotConstants.SET_MODE_IOT_FLOW);
                } else {
                    item.setWorkMode(deviceCache.getWorkMode());
                }
                if (deviceCache == null || deviceCache.getSetOpening() == null){
                    item.setSetOpening(0);
                }else {
                    item.setSetOpening(deviceCache.getSetOpening());
                }
                if (deviceCache == null || deviceCache.getLockState() == null){
                    item.setLockState(0);
                }else {
                    item.setLockState(deviceCache.getLockState());
                }
                if (deviceCache == null || deviceCache.getValveOpening() == null){
                    item.setValveOpening(0);
                }else {
                    item.setValveOpening(deviceCache.getValveOpening());
                }
                if (deviceCache == null || deviceCache.getTempIntake() == null){
                    item.setTempIntake(new BigDecimal("0"));
                }else {
                    item.setTempIntake(deviceCache.getTempIntake());
                }
                if (deviceCache == null || deviceCache.getTempReturn() == null){
                    item.setTempReturn(new BigDecimal("0"));
                }else {
                    item.setTempReturn(deviceCache.getTempReturn());
                }
                if (deviceCache == null || deviceCache.getTimeUpload() == null){
                    item.setTimeUpload(null);
                }else {
                    item.setTimeUpload(deviceCache.getTimeUpload());
                }
                if (deviceCache == null || deviceCache.getTimeSample() == null){
                    item.setTimeSample(null);
                }else {
                    item.setTimeSample(deviceCache.getTimeSample());
                }

            }
        });
        return getDataTable(list);
    }

    /**
     * 获取热表历史数据
     */
    @PreAuthorize("@ss.hasPermi('system:device:list')")
    @GetMapping("/heat/history/data/{timeType}")
    public AjaxResult heatHistoryData(@PathVariable String timeType, SysDevice sysDevice)
    {
        LambdaEsQueryWrapper<EsDeviceDataInfo> wrapper = new LambdaEsQueryWrapper<>();
        wrapper.eq(EsDeviceDataInfo::getDeviceCode, sysDevice.getDeviceCode())
                .index(IotConstants.IOT_DEVICE_TABLE_NAME + getDeptId());
        String colum = "0".equals(timeType) ? "createTime.keyword" : "timeSample.keyword";
        //0上报时间1采集时间
        QueryBuilder queryBuilder = QueryBuilders.rangeQuery(colum)
                .from(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,sysDevice.getBeginDate()))
                .to(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,sysDevice.getEndDate()))
                .format(DateUtils.YYYY_MM_DD_HH_MM_SS);
        wrapper.mix(queryBuilder);
        return AjaxResult.success(esDeviceInfoMapper.selectList(wrapper));
    }

    /**
     * 获取阀门历史数据
     */
    @PreAuthorize("@ss.hasPermi('system:device:list')")
    @GetMapping("/value/history/data/{timeType}")
    public AjaxResult valueHistoryData(@PathVariable String timeType, SysDevice sysDevice)
    {
        LambdaEsQueryWrapper<EsValueInfo> wrapper = new LambdaEsQueryWrapper<>();
        wrapper.eq(EsValueInfo::getDeviceCode, sysDevice.getDeviceCode())
                .index(IotConstants.IOT_VALUE_TABLE_NAME + getDeptId());
        String colum = "0".equals(timeType) ? "createTime.keyword" : "timeSample.keyword";
        //0上报时间1采集时间
        QueryBuilder queryBuilder = QueryBuilders.rangeQuery(colum)
                .from(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,sysDevice.getBeginDate()))
                .to(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,sysDevice.getEndDate()))
                .format(DateUtils.YYYY_MM_DD_HH_MM_SS);
        wrapper.mix(queryBuilder);
        return AjaxResult.success(esValueInfoMapper.selectList(wrapper));
    }
    /**
     * 同步历史数据,暂时没用
     * @param sysDevice
     * @return
     */
    @PostMapping("/history/data")
    public AjaxResult loadHistoryData(@RequestBody  SysDevice sysDevice)
    {
        LambdaEsQueryWrapper<EsDeviceInfo> wrapper = new LambdaEsQueryWrapper<>();
        wrapper.eq(EsDeviceInfo::getDeviceCode, sysDevice.getDeviceCode())
                .index(IotConstants.IOT_DEVICE_TABLE_NAME + getDeptId());
//        esDeviceInfoMapper.delete(wrapper);
        if ("true".equals(redisCache.getCacheObject(CacheConstants.SYNC_DEVICE))){
            return AjaxResult.error("正在同步设备，请稍后");
        }
        sysDeviceService.syncHistoryDevice(sysDevice.getDeviceCode());
        return success();
    }
    /**
     * 查询设备列表
     */
    @PreAuthorize("@ss.hasPermi('system:device:list')")
    @GetMapping("/iot/device/list")
    public TableDataInfo iotDevicelist(SysDevice sysDevice)
    {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();
        BaseResult<PageResult<DeviceListResult>> result = secondDeviceAsyncClient.getDeviceList(pageNum, pageSize);
        List<String> deviceCodes = result.getData().getItems().stream().map(DeviceListResult::getNodeId).collect(Collectors.toList());

        List<IotDeviceBindResult> resultList = sysDeviceService.checkDeviceCodeImport(deviceCodes);
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setRows(resultList);
        rspData.setTotal(result.getData().getTotal());
        return rspData;
    }
    /**
     * 通过设备code查询设备
     */
    @PreAuthorize("@ss.hasPermi('system:device:list')")
    @GetMapping("/iot/{deviceCode}")
    public AjaxResult getInfo(@PathVariable("deviceCode") String deviceCode)
    {
        SysDevice device = sysDeviceService.selectSysDeviceByDeviceCode(deviceCode,getDeptId());
        if (Objects.isNull(device)){
            return AjaxResult.error("设备不存在");
        }
        if (device.getBuildingId() != null) {
            device.setBuildingInfo(sysBuildingService.selectSysBuildingByBuildingId(device.getBuildingId()));
        }

        return success(device);
    }


    /**
     * 导出设备列表
     */
    @PreAuthorize("@ss.hasPermi('system:device:export')")
    @Log(title = "设备", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, SysDevice sysDevice)
    {
        sysDevice.setDeptId(getDeptId());
        List<SysDevice> list = sysDeviceService.selectSysDeviceList(sysDevice);
        ExcelUtil<SysDevice> util = new ExcelUtil<SysDevice>(SysDevice.class);
        util.exportExcel(response, list, "设备数据");
    }

    /**
     * 获取设备详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:device:query')")
    @GetMapping(value = "/{deviceId}")
    public AjaxResult getInfo(@PathVariable("deviceId") Long deviceId)
    {
        return success(sysDeviceService.selectSysDeviceByDeviceId(deviceId));
    }

    /**
     * 新增设备
     */
    @PreAuthorize("@ss.hasPermi('system:device:add')")
    @Log(title = "设备", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody SysDevice sysDevice)
    {
        sysDevice.setDeptId(getDeptId());
        return toAjax(sysDeviceService.insertSysDevice(sysDevice));
    }

    /**
     * 新增设备
     */
    @PreAuthorize("@ss.hasPermi('system:device:add')")
    @Log(title = "设备", businessType = BusinessType.INSERT)
    @PostMapping("/insert/{deviceCode}")
    public AjaxResult add(@PathVariable String deviceCode)
    {
        if (sysDeviceService.selectSysDeviceByDeviceCode(deviceCode, getDeptId()) == null){
            BaseResult<PageResult<DeviceListResult>> result =  secondDeviceAsyncClient.getDeviceInfo(deviceCode);
            if (result.getCode() == 200){
                PageResult<DeviceListResult> extendDict = result.getData();
                if (extendDict != null){
                    SysDevice sysDevice = SysDevice.of(extendDict.getItems().get(0));
                    sysDevice.setCreateBy(getUsername());
                    sysDevice.setDeptId(getDeptId());
                    sysDevice.setDeviceCode(deviceCode);
                    return toAjax(sysDeviceService.insertSysDevice(sysDevice));
                }else {
                    return AjaxResult.error("设备编号不存在");
                }
            } else {
                return AjaxResult.error(result.getMessage());
            }
        } else {
            return AjaxResult.error("设备已存在");
        }

    }

    /**
     * 一键同步设备
     */
    @PreAuthorize("@ss.hasPermi('system:device:add')")
    @Log(title = "一键同步设备", businessType = BusinessType.INSERT)
    @PostMapping("/sync")
    public AjaxResult syncDevice()
    {
        redisCache.setCacheObject(CacheConstants.SYNC_DEVICE,"false");

        if ("true".equals(redisCache.getCacheObject(CacheConstants.SYNC_DEVICE))){
            return AjaxResult.error("正在同步设备，请稍后");
        }
        sysDeviceService.syncDevice(getUsername(), getDeptId());
        return success();
    }

    /**
     * 设置iot设备开阀 关阀
     */
    @PreAuthorize("@ss.hasPermi('system:device:value')")
    @Log(title = "操作阀门", businessType = BusinessType.VALUE)
    @PutMapping("/iot/updateValue")
    public AjaxResult setStatus(@RequestBody SetIotParams params)
    {
//        IotResult<Object>  result= deviceAsyncClient.setValve(params.getDeviceCode(), params.getValveStatus(), params.getAngle());
//        if (result.getCode() == 0){
//            return success(result.getData());
//        } else {
//            return error(result.getMsg());
//        }
        return success();
    }
    /**
     * 修改设备
     */
    @PreAuthorize("@ss.hasPermi('system:device:edit')")
    @Log(title = "设备", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody SysDevice sysDevice)
    {
        sysDevice.setUpdateBy(getUsername());
        return toAjax(sysDeviceService.updateSysDevice(sysDevice));
    }

    /**
     * 设备绑定
     */
    @PreAuthorize("@ss.hasPermi('system:device:edit')")
    @Log(title = "设备绑定", businessType = BusinessType.UPDATE)
    @PostMapping("/iot/bind")
    public AjaxResult iotBind(@RequestBody SysDevice sysDevice)
    {
        SysDevice dbDevice = sysDeviceService.selectSysDeviceByDeviceCode(sysDevice.getDeviceCode(), getDeptId());
        if (dbDevice == null){
            return AjaxResult.error("设备编号不存在");
        }
        sysDevice.setUpdateBy(getUsername());
        sysDevice.setRegisterBy(getUsername());

        //如果是阀门 ，则查询阀门信息,并缓存相关配置信息
        if (dbDevice.getDeviceType().equals(IotConstants.DEVICE_TYPE_VALVE)){
            readValueFromIot(dbDevice);
        }
        return toAjax(sysDeviceService.updateSysDeviceWithCode(sysDevice));

    }

    /**
     * 设备接触绑定设备解除绑定
     */
    @PreAuthorize("@ss.hasPermi('system:device:edit')")
    @Log(title = "设备解除绑定", businessType = BusinessType.UPDATE)
    @PostMapping("/iot/unbind")
    public AjaxResult iotUnbind(@RequestBody SysDevice sysDevice)
    {
        SysDevice dbDevice = sysDeviceService.selectSysDeviceByDeviceCode(sysDevice.getDeviceCode(), getDeptId());
        if (dbDevice == null){
            return AjaxResult.error("设备编号不存在");
        }
        sysDevice.setUpdateBy(getUsername());
        sysDevice.setRegisterBy(getUsername());
        sysDevice.setUnBind("1");
        return toAjax(sysDeviceService.updateSysDeviceWithCode(sysDevice));
    }

    /**
     * 同步设备数据
     * @param sysDevice
     */
    private ValueResult readValueFromIot(SysDevice sysDevice)
    {
        // 创建一个新的列表来存放每批数据
        List<String> batchList = new ArrayList<>();
        batchList.add(sysDevice.getDeviceCode());
        // 读取阀门信息
        BaseResult<List<ValueResult>> result = secondDeviceAsyncClient.readStatusSync(batchList);
        if (result.getCode() == 200){
            List<ValueResult> data = result.getData();
            if (!data.isEmpty()){
                ValueResult valueResult = data.get(0);
                DeviceCache deviceCache = redisCache.getCacheObject(CacheConstants.IOT_DEVICE + valueResult.getNodeId());
                if (deviceCache == null){
                    deviceCache = new DeviceCache();
                }
                //设置设备信息
                deviceCache.update(valueResult);
                redisCache.setCacheObject(CacheConstants.IOT_DEVICE + valueResult.getNodeId(), deviceCache);
                return valueResult;
            }
        }
        throw new ServiceException(result.getMessage());

    }
    /**
     * 删除设备
     */
    @PreAuthorize("@ss.hasPermi('system:device:remove')")
    @Log(title = "设备", businessType = BusinessType.DELETE)
	@DeleteMapping("/{deviceIds}")
    public AjaxResult remove(@PathVariable Long[] deviceIds)
    {
        return toAjax(sysDeviceService.deleteSysDeviceByDeviceIds(deviceIds));
    }

//    /**
//     * 开阀门
//     */
//    @PreAuthorize("@ss.hasPermi('system:device:edit')")
//    @Log(title = "开阀门", businessType = BusinessType.UPDATE)
//    @PutMapping("/openValue")
//    public AjaxResult openValue(@RequestBody SysDevice sysDevice)
//    {
//        sysDevice.setUpdateBy(getUsername());
//        Date date = DateUtils.getNowDate();
//        String expressDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.addMinutes(date, 2));
//        SysDevice dbDevice = sysDeviceService.selectSysDeviceByDeviceId(sysDevice.getDeviceId());
//        //先打开阀门，设置开度100
//        BaseResult<SetResult> setResult = secondDeviceAsyncClient.setOpening(
//                date.getTime(),
//                dbDevice.getDeviceCode(),
//                100 ,
//                expressDate);
//        if (checkIotSetStatus(setResult)) {
//            //设置为室温模式
//            setResult = secondDeviceAsyncClient.setWorkMode(
//                    date.getTime(),
//                    dbDevice.getDeviceCode(),
//                    IotConstants.SET_MODE_IOT_TEMP ,
//                    expressDate);
//            if (checkIotSetStatus(setResult)) {
//                return toAjax(sysDeviceService.updateSysDevice(sysDevice));
//            } else {
//                return AjaxResult.error(this.getSetErrorMsg(setResult));
//            }
//        } else {
//            return AjaxResult.error(this.getSetErrorMsg(setResult));
//        }
//    }
//
//    /**
//     * 关阀门
//     */
//    @PreAuthorize("@ss.hasPermi('system:device:edit')")
//    @Log(title = "关阀门", businessType = BusinessType.UPDATE)
//    @PutMapping("/closeValue")
//    public AjaxResult closeValue(@RequestBody SysDevice sysDevice)
//    {
//        sysDevice.setUpdateBy(getUsername());
//        Date date = DateUtils.getNowDate();
//        String expressDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.addMinutes(date, 2));
//        SysDevice dbDevice = sysDeviceService.selectSysDeviceByDeviceId(sysDevice.getDeviceId());
//        //设置为通断模式
//        BaseResult<SetResult> setResult= secondDeviceAsyncClient.setWorkMode(
//                date.getTime(),
//                dbDevice.getDeviceCode(),
//                IotConstants.SET_MODE_IOT_FLOW ,
//                expressDate);
//        if (checkIotSetStatus(setResult)) {
//            //设置阀门开度
//            secondDeviceAsyncClient.setOpening(
//                    date.getTime(),
//                    dbDevice.getDeviceCode(),
//                    0 ,
//                    expressDate);
//            if (checkIotSetStatus(setResult)) {
//                return toAjax(sysDeviceService.updateSysDevice(sysDevice));
//            } else {
//                return AjaxResult.error(this.getSetErrorMsg(setResult));
//            }
//        } else {
//            return AjaxResult.error(this.getSetErrorMsg(setResult));
//        }
//    }


    /**
     * 设置阀门开度
     */
    @PreAuthorize("@ss.hasPermi('system:device:edit')")
    @Log(title = "设置阀门开度", businessType = BusinessType.UPDATE)
    @PutMapping("/setOpening")
    public AjaxResult setOpening(@RequestBody SysDevice sysDevice)
    {
        Date date = DateUtils.getNowDate();
        String expressDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.addMinutes(date, 2));
        SysDevice dbDevice = sysDeviceService.selectSysDeviceByDeviceId(sysDevice.getDeviceId());
        DeviceCache deviceCache = redisCache.getCacheObject(CacheConstants.IOT_DEVICE + dbDevice.getDeviceCode());
        if (!deviceCache.getWorkMode().equals(IotConstants.SET_MODE_IOT_FLOW)){
            return AjaxResult.warn("请先设置流量平衡模式");
        }
        BaseResult<SetResult> setResult = //设置阀门开度
                secondDeviceAsyncClient.setOpening(
                        date.getTime(),
                        dbDevice.getDeviceCode(),
                        sysDevice.getSetOpening() ,
                        expressDate);
        if (checkIotSetStatus(setResult)) {
            secondDeviceAsyncClient.getStatus(1L, dbDevice.getDeviceCode(), expressDate);
            BaseResult<Map<String, Object>> checkResult = checkIotResult(1L, dbDevice.getDeviceCode(), expressDate, 0);
            if (String.valueOf(checkResult.getData().get("setOpening")).equals( sysDevice.getSetOpening()+"")){
                sysDevice.setUpdateBy(getUsername());
                sysDeviceService.updateSysDevice(sysDevice);
                return success(readValueFromIot(dbDevice));
            } else {
                return AjaxResult.error("设置失败");
            }
        } else {
            return AjaxResult.error(this.getSetErrorMsg(setResult));
        }
    }
    /**
     * 设置锁定模式
     */
    @PreAuthorize("@ss.hasPermi('system:device:edit')")
    @Log(title = "设置锁定模式", businessType = BusinessType.UPDATE)
    @PutMapping("/setMode")
    public AjaxResult setMode(@RequestBody SysDevice sysDevice)
    {
        Date date = DateUtils.getNowDate();
        String expressDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.addMinutes(date, 2));
        SysDevice dbDevice = sysDeviceService.selectSysDeviceByDeviceId(sysDevice.getDeviceId());
        BaseResult<SetResult> setResult = secondDeviceAsyncClient.setLockTemp(date.getTime(), dbDevice.getDeviceCode(), sysDevice.getSetMode() , expressDate);
        DeviceCache deviceCache = redisCache.getCacheObject(CacheConstants.IOT_DEVICE + dbDevice.getDeviceCode());
        if (!deviceCache.getWorkMode().equals(IotConstants.SET_MODE_IOT_TEMP)){
            return AjaxResult.warn("请先设置室温模式");
        }
        if (checkIotSetStatus(setResult)) {
            secondDeviceAsyncClient.getStatus(2L, dbDevice.getDeviceCode(), expressDate);
            BaseResult<Map<String, Object>> checkResult = checkIotResult(2L, dbDevice.getDeviceCode(), expressDate, 0);
            if (checkResult.getData().get("lockState").toString().equals(sysDevice.getSetMode() + "")){
                sysDevice.setUpdateBy(getUsername());
                sysDeviceService.updateSysDevice(sysDevice);
                return success(readValueFromIot(dbDevice));
            } else {
                return AjaxResult.error("设置失败");
            }
        } else {
            return AjaxResult.error(this.getSetErrorMsg(setResult));
        }
    }

    /**
     * 设置回水温度
     */
    @PreAuthorize("@ss.hasPermi('system:device:edit')")
    @Log(title = "设置回水温度", businessType = BusinessType.UPDATE)
    @PutMapping("/setReturnTemp")
    public AjaxResult setReturnTemp(@RequestBody SysDevice sysDevice)
    {
        Date date = DateUtils.getNowDate();
        String expressDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.addMinutes(date, 2));
        SysDevice dbDevice = sysDeviceService.selectSysDeviceByDeviceId(sysDevice.getDeviceId());
        DeviceCache deviceCache = redisCache.getCacheObject(CacheConstants.IOT_DEVICE + dbDevice.getDeviceCode());
        if (!deviceCache.getWorkMode().equals(IotConstants.SET_MODE_IOT_WATER)){
            return AjaxResult.warn("请先设置回水模式");
        }
        BaseResult<SetResult> setResult = secondDeviceAsyncClient.setReturnTemp(date.getTime(),
                dbDevice.getDeviceCode(),
                sysDevice.getSetTemp().setScale(1, RoundingMode.HALF_UP) ,
                expressDate);
        if (checkIotSetStatus(setResult)) {
            secondDeviceAsyncClient.getStatus(3L, dbDevice.getDeviceCode(), expressDate);
            BaseResult<Map<String, Object>> checkResult = checkIotResult(3L, dbDevice.getDeviceCode(), expressDate, 0);
            if (new BigDecimal(String.valueOf(checkResult.getData().get("returnTemp"))).compareTo( sysDevice.getSetTemp()) == 0){
                sysDevice.setUpdateBy(getUsername());
                sysDeviceService.updateSysDevice(sysDevice);
                return success(readValueFromIot(dbDevice));
            } else {
                return AjaxResult.error("设置失败");
            }
        } else {
            return AjaxResult.error(this.getSetErrorMsg(setResult));
        }
    }
    /**
     * 设置温度
     */
    @PreAuthorize("@ss.hasPermi('system:device:edit')")
    @Log(title = "设置温度", businessType = BusinessType.UPDATE)
    @PutMapping("/setTemp")
    public AjaxResult setTemp(@RequestBody SysDevice sysDevice)
    {
        Date date = DateUtils.getNowDate();
        String expressDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.addMinutes(date, 2));
        SysDevice dbDevice = sysDeviceService.selectSysDeviceByDeviceId(sysDevice.getDeviceId());
        DeviceCache deviceCache = redisCache.getCacheObject(CacheConstants.IOT_DEVICE + dbDevice.getDeviceCode());
        if (!deviceCache.getWorkMode().equals(IotConstants.SET_MODE_IOT_TEMP)){
            return AjaxResult.warn("请先设置室温模式");
        }
        if (dbDevice.getSetMode() == 0 ){
            return AjaxResult.warn("请先设置锁定模式");
        }
        BaseResult<SetResult> setResult = secondDeviceAsyncClient.setRoomTemp(date.getTime(),
                                                                                dbDevice.getDeviceCode(),
                                                                                sysDevice.getSetTemp().setScale(1, RoundingMode.HALF_UP) ,
                                                                                sysDevice.getSetTemp().setScale(1, RoundingMode.HALF_UP),
                                                                                expressDate);
        if (checkIotSetStatus(setResult)) {
            secondDeviceAsyncClient.getStatus(4L, dbDevice.getDeviceCode(), expressDate);
            BaseResult<Map<String, Object>> checkResult = checkIotResult(4L, dbDevice.getDeviceCode(), expressDate, 0);
            if (new BigDecimal(String.valueOf(checkResult.getData().get("settingTemp"))).compareTo( sysDevice.getSetTemp()) == 0){
                sysDevice.setUpdateBy(getUsername());
                sysDeviceService.updateSysDevice(sysDevice);
                return success(readValueFromIot(dbDevice));
            } else {
                return AjaxResult.error("设置失败");
            }
        } else {
            return AjaxResult.error(this.getSetErrorMsg(setResult));
        }
    }

    /**
     * 设置工作模式
     */
    @PreAuthorize("@ss.hasPermi('system:device:edit')")
    @Log(title = "设置工作模式", businessType = BusinessType.UPDATE)
    @PutMapping("/setWorkMode")
    public AjaxResult setWorkMode(@RequestBody SysDevice sysDevice)
    {
        Date date = DateUtils.getNowDate();
        String expressDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.addMinutes(date, 2));
        SysDevice dbDevice = sysDeviceService.selectSysDeviceByDeviceId(sysDevice.getDeviceId());
        BaseResult<SetResult> setResult = secondDeviceAsyncClient.setWorkMode(date.getTime(), dbDevice.getDeviceCode(), sysDevice.getWorkMode() , expressDate);
        if (checkIotSetStatus(setResult)){
            secondDeviceAsyncClient.getStatus(5L, dbDevice.getDeviceCode(), expressDate);
            BaseResult<Map<String, Object>> checkResult = checkIotResult(5L, dbDevice.getDeviceCode(), expressDate, 0);
            if(checkResult.getData().get("workMode").toString().equals(sysDevice.getWorkMode())){
                sysDevice.setUpdateBy(getUsername());
                sysDeviceService.updateSysDevice(sysDevice);
                return success(readValueFromIot(dbDevice));
            } else {
                return AjaxResult.error("设置失败");
            }
        } else {
            return AjaxResult.error(setResult.getMessage());
        }
    }

    /**
     * 一键开关阀
     * @return
     */
    @PreAuthorize("@ss.hasPermi('system:device:edit')")
    @Log(title = "一键开关阀", businessType = BusinessType.UPDATE)
    @PutMapping("/selfLockMany")
    public AjaxResult selfLockMany(@RequestBody List<LockParam> lockParamList)
    {
        //校验状态
        BaseResult<List<String>> checkResult = secondDeviceAsyncClient.selfLockMany(lockParamList);
        if (checkResult.getCode() == 200){
            List<String> data = checkResult.getData();
            return success(data);
        } else {
            return error(checkResult.getMessage());
        }
    }
    /**
     * 批量工作模式
     * @return
     */
    @PreAuthorize("@ss.hasPermi('system:device:edit')")
    @Log(title = "批量工作模式", businessType = BusinessType.UPDATE)
    @PutMapping("/setWorkModeBatch")
    public AjaxResult setWorkModeBatch(@RequestBody List<WorkModeParam> workModeParams)
    {
        //校验状态
        BaseResult<List<String>> checkResult = secondDeviceAsyncClient.setWorkModeBatch(workModeParams);
        if (checkResult.getCode() == 200){
            List<String> data = checkResult.getData();
            return success(data);
        } else {
            return error(checkResult.getMessage());
        }
    }

    /**
     * 批量设置温控器锁定 1 是开锁定，0 是关锁定
     * @return
     */
    @PreAuthorize("@ss.hasPermi('system:device:edit')")
    @Log(title = "批量设置温控器锁定", businessType = BusinessType.UPDATE)
    @PutMapping("/setPanelLockTempBatch")
    public AjaxResult setPanelLockTempBatch(@RequestBody List<LockStateParam> lockStateParams)
    {
        //校验状态
        BaseResult<List<String>> checkResult = secondDeviceAsyncClient.setPanelLockTempBatch(lockStateParams);
        if (checkResult.getCode() == 200){
            List<String> data = checkResult.getData();
            return success(data);
        } else {
            return error(checkResult.getMessage());
        }
    }


    /**
     * 批量设置温控器温度
     * @return
     */
    @PreAuthorize("@ss.hasPermi('system:device:edit')")
    @Log(title = "批量设置温控器温度", businessType = BusinessType.UPDATE)
    @PutMapping("/setPanelSettingTempBatch")
    public AjaxResult setPanelSettingTempBatch(@RequestBody List<SettingTempParam> settingTempParams)
    {
        //校验状态
        BaseResult<List<String>> checkResult = secondDeviceAsyncClient.setPanelSettingTempBatch(settingTempParams);
        if (checkResult.getCode() == 200){
            List<String> data = checkResult.getData();
            return success(data);
        } else {
            return error(checkResult.getMessage());
        }
    }

    /**
     * 批量读取数据
     */
    @PreAuthorize("@ss.hasPermi('system:device:edit')")
    @Log(title = "批量读取数据", businessType = BusinessType.UPDATE)
    @PutMapping("/readStatusSync")
    public AjaxResult readStatusSync(@RequestBody List<String> nodeIdList)
    {
        //校验状态
        BaseResult<List<ValueResult>> checkResult = secondDeviceAsyncClient.readStatusSync(nodeIdList);
        if (checkResult.getCode() == 200){
            List<ValueResult> data = checkResult.getData();
            data.forEach(valueResult -> {
                DeviceCache deviceCache = redisCache.getCacheObject(CacheConstants.IOT_DEVICE + valueResult.getNodeId());
                if (deviceCache == null) {
                    deviceCache = new DeviceCache();
                }
                //更新开关阀状态
                sysDeviceService.updateDeviceStatus(deviceCache, valueResult);
                deviceCache.update(valueResult);
                redisCache.setCacheObject(CacheConstants.IOT_DEVICE + valueResult.getNodeId(), deviceCache);
            });
            return success(data);
        } else {
            return error(checkResult.getMessage());
        }
    }


    /**
     * 读取设备结果状态，递归十次
     */
    private BaseResult<Map<String, Object>> checkIotResult(Long msgId,String nodeId,String expiredDate, int count){
        if (count > 10){
            throw new RuntimeException("设置失败");
        }
        //校验状态
        BaseResult<Map<String, Object>> checkResult = secondDeviceAsyncClient.getStatusResult(msgId, nodeId, expiredDate);
        if (checkIotReadStatus(checkResult)){
            return checkResult;
        }else {
            return checkIotResult(msgId, nodeId, expiredDate, count + 1);
        }
    }


    /**
     * 检查设备是否设置成功
     * @param setResult
     * @return
     */
    private boolean checkIotSetStatus(BaseResult<SetResult> setResult){
        if (setResult.getCode() == 200){
            return setResult.getData().getErrCode() == 0;
        } else {
            return false;
        }
    }

    private String getSetErrorMsg(BaseResult<SetResult> setResult){
        if (setResult.getCode() == 200){
            if(setResult.getData().getErrCode() == 0){
                return "";
            } else {
                return setResult.getData().getErrMsg();
            }
        } else {
            if (setResult.getData() != null) {
                return setResult.getData().getErrMsg();
            }
            return setResult.getMessage();
        }
    }

    /**
     * 检查设备是否读取成功
     * @param checkResult
     * @return
     */
    private boolean checkIotReadStatus(BaseResult<Map<String, Object>> checkResult){
        if (checkResult.getCode() == 200){
            Map<String, Object> data = checkResult.getData();
            Integer errCode = (Integer) data.get("errCode");
            return errCode == 0;
        } else {
            return false;
        }
    }
    private String getReadErrorMsg(BaseResult<Map<String, Object>> checkResult){
        if (checkResult.getCode() == 200){
            Map<String, Object> data = checkResult.getData();
            Integer errCode = (Integer) data.get("errCode");
            if(errCode == 0){
                return "";
            } else {
                return (String) data.get("errMsg");
            }
        } else {
            if (checkResult.getData() != null) {
                Map<String, Object> data = checkResult.getData();
                return (String) data.get("errMsg");
            }
            return checkResult.getMessage();
        }
    }

}
